home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
...taking it to the Macs!
/
...taking it to the Macs!.iso
/
Extras
/
ActiveX Mac SDK
/
ActiveX SDK
/
Container Common
/
CBaseSite.cpp
< prev
next >
Wrap
Text File
|
1997-01-03
|
17KB
|
895 lines
//
// XSITE.CPP
//
// Copyright (C) Microsoft Corporation, 1996
//
#include "headers.h"
#include <ctype.h>
#include "MacMisc.h"
#include "CActiveXScheduler.h"
static CCodeDownload* CodeDownload;
static void toLower(char* src);
static LPOLESTR StrDup(LPCOLESTR psz);
#pragma mark === CBaseSite::Construction & Destruction ===
/*************************** Construction/Destruction *****************/
//
// CBaseSite::CreateCBaseSite
//
CXSite *CXSite::CreateSite(void)
{
return new CXSite();
}
//
// CBaseSite::CBaseSite
//
CXSite::CXSite(void)
{
m_ClientInstance = 0L;
m_pszCodeURL = NULL;
m_BaseURL = NULL;
m_dwMinimumVersion = 0L;
m_fHaveInitialStream = false;
#ifdef PLUGIN_ADAPTER
m_pInitialDataStreamNotify = NULL;
m_pUnattachedList = NULL;
#endif
m_punkObject = NULL;
mUnkOuter = nil;
mContainerP = nil;
mContainerData = NULL;
mObjSiteP = NULL;
mControlP = NULL;
mPropertyBagP = NULL;
mContextCount = 1;
mCachedDraw = false;
mCachedContextChange = false;
mCachedActiveContextID = InvalidContextID;
mHavePort = false;
mOldPortState.ClipRgn = NULL;
mBindHostP = NULL;
mThreadScheduler = NULL;
mDestroyed = false;
}
//
// CBaseSite::~CBaseSite
//
CXSite::~CXSite(void)
{
#ifdef PLUGIN_ADAPTER
if (m_pInitialDataStreamNotify != NULL)
delete m_pInitialDataStreamNotify;
#endif
if (m_BaseURL != NULL)
CoTaskMemFree(m_BaseURL);
if (m_pszCodeURL != NULL)
// CoTaskMemFree(m_pszCodeURL);
DisposePtr(m_pszCodeURL);
if ( mContainerP )
mContainerP->Release();
if ( mBindHostP )
delete mBindHostP;
}
#pragma mark === CBaseSite::Non Interface functions ===
//
// CBaseSite::AddParam
//
STDMETHODIMP
CXSite::AddParam (Char8* inName, Char8* inValue)
{
LPOLESTR LowerCaseName = StrDup(inName);
if ( LowerCaseName )
toLower(LowerCaseName);
else
return E_OUTOFMEMORY;
if ( !mPropertyBagP )
{
if ((mPropertyBagP = new CPropertyBag()) == NULL)
return E_OUTOFMEMORY;
}
if (strcmp(LowerCaseName, "codebase") == 0)
{
if ((m_pszCodeURL = (LPOLESTR)StrDup((Char8*)inValue)) != NULL)
{
GetVersionFromURL(m_pszCodeURL, &m_dwMinimumVersion);
}
}
else if (strcmp(LowerCaseName, "classid") == 0)
{
toLower(inValue);
if( strncmp(inValue, "clsid:", 6) == 0)
CLSIDFromString((Char8*)inValue + 6, &m_clsid);
}
else
{
mPropertyBagP->AddParam(LowerCaseName, inValue );
}
DisposePtr(LowerCaseName);
return S_OK;
}
//
// CBaseSite::FindControl
//
#define kCLSIDConst "CLSID\\"
STDMETHODIMP
CXSite::FindControl(void)
{
HKEY hKey;
char* CLSIDString;
char Key[256];
StringFromCLSID(m_clsid, &CLSIDString);
Key[0] = '\0';
strcat(Key, kCLSIDConst);
strcat(Key, CLSIDString);
#undef CoTaskMemFree // StringFromCLSID used CoTaskMemAlloc so don't us debug version
CoTaskMemFree(CLSIDString);
#ifdef CHECKMEMORYLEAKS
#define CoTaskMemFree DebugCoTaskMemFree
#endif
if (RegOpenKey(HKEY_CLASSES_ROOT, Key, &hKey) == S_OK)
{
RegCloseKey(hKey);
return S_OK;
}
else if (m_pszCodeURL == NULL ||
GetFileTypeFromExtension(m_pszCodeURL) == FILEXTN_UNKNOWN)
return E_UNEXPECTED;
return S_OK;
}
//
// CBaseSite::CreateControl
//
STDMETHODIMP
CXSite::CreateControl(Boolean8 inDoDownload)
{
ErrorCode Result;
LPUNKNOWN punkPersist;
if (m_punkObject != NULL || mDestroyed)
return E_ABORT;
if(!mBindHostP)
mBindHostP = new CBindHost(this);
// Attempt to create the object. The latest OLE Controls guidelines only
// require the object to support IUnknown.
if (FAILED(Result = CoCreateInstance(m_clsid, NULL, CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID *) &m_punkObject)))
{
// if we need to download, and the client says it is okay, do it
// otherwise, just pass the error back so the client can deal with it
if ( Result == REGDB_E_CLASSNOTREG || Result == CO_E_DLLNOTFOUND)
{
if (m_pszCodeURL == NULL ||
GetFileTypeFromExtension(m_pszCodeURL) == FILEXTN_UNKNOWN)
return E_UNEXPECTED;
if(!inDoDownload )
return Result;
// Create the download object for this container if not already available.
if (CodeDownload == NULL)
{
if ((CodeDownload = new CCodeDownload()) == NULL)
return E_FAIL;
}
AddRef(); // accout for this pointer
CodeDownload->QueueDownload(this);
return E_PENDING;
}
return E_FAIL;
}
// See if this is an in-proc object
if (SUCCEEDED(m_punkObject->QueryInterface(IID_IObjectWithSite, (LPVOID *) &mObjSiteP)))
{
mObjSiteP->SetSite((IUnknown*) (void*) this);
if (FAILED(m_punkObject->QueryInterface(IID_IControl, (LPVOID *) &mControlP)))
mControlP = nil;
}
else
mObjSiteP = NULL;
if ( !mControlP )
goto CreateFailure;
if (SUCCEEDED(m_punkObject->QueryInterface(IID_IPersistPropertyBag,(LPVOID *) &punkPersist)))
{
Result = ((LPPERSISTPROPERTYBAG) punkPersist)->Load( mPropertyBagP, NULL);
punkPersist->Release();
}
#ifdef PLUGIN_ADAPTER
else if (m_pInitialDataStreamNotify != NULL &&
SUCCEEDED(m_punkObject->QueryInterface(IID_IPersistStream,
(LPVOID *) &punkPersist)))
{
m_pInitialDataStreamNotify->m_SeekPosition = sizeof(CLSID);
Result = ((LPPERSISTSTREAM) punkPersist)->Load((LPSTREAM)
m_pInitialDataStreamNotify);
punkPersist->Release();
}
delete m_pInitialDataStreamNotify;
m_pInitialDataStreamNotify = NULL;
#endif
if (FAILED(Result))
goto CreateFailure;
if ( mCachedContextChange )
{
UInt32 ContextID;
Int32 Index = 0;
while ( GetContextID(++Index, &ContextID))
{
mControlP->OnContextChange(ContextID, AddContext);
if (ContextID == mCachedActiveContextID)
mControlP->OnContextChange(ContextID, ActivateContext);
}
mCachedContextChange = false;
}
if ( mCachedDraw )
{
DrawControl();
mCachedDraw = false;
}
return S_OK;
// Cleanup after anything that we've already done and unload the object.
CreateFailure:
DestroyControl();
return E_FAIL;
}
//
// CBaseSite::DestroyControl
//
STDMETHODIMP
CXSite::DestroyControl(void)
{
mDestroyed = true;
if ( mPropertyBagP )
ReleaseAndNull(mPropertyBagP);
if(mBindHostP != NULL)
mBindHostP->AbortBindings();
if (mControlP != NULL)
ReleaseAndNull(mControlP);
if (mObjSiteP != NULL)
{
mObjSiteP->SetSite(NULL);
ReleaseAndNull(mObjSiteP);
}
SafeReleaseAndNull(m_punkObject);
CoFreeUnusedLibraries(); // unload the com object if not used
return S_OK;
}
//
// CBaseSite::SetContainerData
//
// Sets the container data for the site
//
STDMETHODIMP
CXSite::SetContainerData(IUnknown* inUnkOuter, void *inContainerData)
{
mUnkOuter = inUnkOuter;
if (mContainerP)
mContainerP->Release();
mUnkOuter->QueryInterface(IID_IContainer, &mContainerP);
mContainerData = inContainerData;
return S_OK;
}
//
// CBaseSite::GetContainerData
//
// Returns the container
//
STDMETHODIMP
CXSite::GetContainerData(void** outContainerData)
{
*outContainerData = mContainerData;
return S_OK;
}
//
// CBaseSite::SetBaseURL
//
// Sets the base URL for this site
//
STDMETHODIMP
CXSite::SetBaseURL(Char8* inURL)
{
if ( m_BaseURL )
{
CoTaskMemFree(m_BaseURL);
m_BaseURL = nil;
}
m_BaseURL = OleStrdup(inURL);
return S_OK;
}
//
// CBaseSite::DrawControl
//
void CXSite::DrawControl(void)
{
if ( mControlP )
{
DrawContext Context = {BeginPortType};
UInt32 ContextID;
long Index = 1;
while( GetContextID(Index++, &ContextID) )
{
AcquireContext(ContextID, &Context);
mControlP->Draw(&Context);
ReleaseContext(&Context);
}
}
else
mCachedDraw = true;
}
//
// CBaseSite::SavePortState
//
void CXSite::SavePortState(PlatformPort* Port)
{
// Save off the current port
::GetPort(&mSavePort);
// Set the current port to the one requested
::SetPort(Port);
// Save off the port rect and clip
mOldPortState.PortRect = Port->portRect;
mOldPortState.ClipRgn = NewRgn();
::GetClip(mOldPortState.ClipRgn);
// Save off the pen state
::GetPenState(&mOldPortState.PenState);
mOldPortState.TextFont = Port->txFont;
mOldPortState.TextMode = Port->txMode;
mOldPortState.TextSize = Port->txSize;
mOldPortState.TextFace = Port->txFace;
::GetForeColor(&mOldPortState.ForeColor);
::GetBackColor(&mOldPortState.BackColor);
}
//
// CBaseSite::RestorePortState
//
void CXSite::RestorePortState(void)
{
// Undo everything we did to "thePort" in AcquirePort.
::SetOrigin(mOldPortState.PortRect.left, mOldPortState.PortRect.top);
if (mOldPortState.ClipRgn)
{
::SetClip(mOldPortState.ClipRgn);
::DisposeRgn(mOldPortState.ClipRgn);
mOldPortState.ClipRgn = NULL;
}
// Restore the current state of things
::SetPenState(&mOldPortState.PenState);
::TextFont(mOldPortState.TextFont);
::TextFace(mOldPortState.TextFace);
::TextMode(mOldPortState.TextMode);
::TextSize(mOldPortState.TextSize);
::RGBForeColor(&mOldPortState.ForeColor);
::RGBBackColor(&mOldPortState.BackColor);
// Set back to original port
::SetPort(mSavePort);
}
//
// CBaseSite::GetContextID
//
// all containers MUST OVERRIDE this
Boolean8
CXSite::GetContextID(Int32 inContextIndex, UInt32* outContextID)
{
#pragma unused (inContextIndex, outContextID)
return false;
}
#pragma mark === CBaseSite::IUnknown Interfaces ===
/************************* IUnknown Interfaces *************************/
//
// CBaseSite::IUnknown::QueryInterface
//
// Returns a pointer to the specified interface on a component to which a
// client currently holds an interface pointer.
//
STDMETHODIMP
CXSite::QueryInterface(REFIID inRefID, void** outObj)
{
ErrorCode Result = CBaseCOM::QueryInterface( inRefID, outObj);
if ( Result == E_NOINTERFACE )
{
void* pv = nil;
if ( inRefID == IID_IControl )
pv = (void*)(IControl*) this;
else if ( inRefID == IID_IContainerSite )
pv = (void*)(IContainerSite*) this;
else if (inRefID == IID_IServiceProvider)
pv = (void*)(LPSERVICEPROVIDER) this;
else if (inRefID == IID_IBindHost)
pv = (void*)(LPBINDHOST) mBindHostP;
else if (inRefID == IID_IThreadScheduler)
pv = (void*)(IThreadScheduler*) this;
*outObj = pv;
if ( pv )
{
((IUnknown*) pv)->AddRef();
Result = S_OK;
}
}
return Result;
}
#pragma mark === CBaseSite::IContainerSite Interfaces ===
//
// CBaseSite::IContainerSite::GetContainer
//
// Returns the container
//
STDMETHODIMP
CXSite::GetContainer(IContainer** outContainer)
{
// Caller's responsibility to AddRef the container interface
*outContainer = mContainerP;
return S_OK;
}
//
// CBaseSite::IContainerSite::RequestFocus
//
// attempt to manage focus
//
STDMETHODIMP
CXSite::RequestFocus ( Boolean8 /* inAcquire */, FocusSet /* inFocus */)
{
return E_NOTIMPL;
}
//
// CBaseSite::RequestSizeChange
//
// how to change the controls size
//
STDMETHODIMP
CXSite::RequestSizeChange ( Point* /* ioSize */)
{
return E_NOTIMPL;
}
//
// CBaseSite::OnChange
//
// Notification that something of interest changed in the control
//
STDMETHODIMP
CXSite::OnChange (ChangeType inChangeType)
{
switch (inChangeType)
{
case UsedAreaChange:
{
DrawContext Context = {BeginPortType};
UInt32 ContextID;
long Index = 1;
while( GetContextID(Index++, &ContextID) )
{
AcquireContext(ContextID, &Context);
::EraseRect(&Context.Location);
ReleaseContext(&Context);
}
}
break;
case ViewChange:
case DataChange:
default:
break;
}
return S_OK; // we don't care here
}
//
// CBaseSite::IContainerSite::AcquireContext
//
STDMETHODIMP
CXSite::AcquireContext(Uint32 /*inContextID*/, DrawContext* /*outContext*/)
{
return E_FAIL;
}
//
// CBaseSite::IContainerSite::ReleaseContext
//
STDMETHODIMP
CXSite::ReleaseContext(DrawContext* inContext)
{
#pragma unused (inContext)
if (!mHavePort)
{
// Unbalanced GetDC/ReleaseDC calls. Return an error.
return E_FAIL;
}
RestorePortState();
mHavePort = FALSE;
return S_OK;
}
//
// CBaseSite::IContainerSite::SetIdleTime
//
STDMETHODIMP
CXSite::SetIdleTime(Int32 inWaitTicks, Uint32 inRefCon)
{
CActiveXScheduler* Scheduler = CActiveXScheduler::GetActiveXScheduler(true);
ErrorCode Result = E_FAIL;
if (Scheduler)
{
if (inWaitTicks == RemoveAllIdlers)
Result = Scheduler->RemoveControl(this);
else if (inWaitTicks == RemoveIdler)
Result = Scheduler->RemoveControlByRefCon(this, inRefCon);
else
{
Result = Scheduler->ScheduleControl(inWaitTicks == IdleAfterAllEvents, inWaitTicks, this, inRefCon);
}
}
return Result;
}
#pragma mark === CBaseSite::IControl Interfaces ===
//
// CBaseSite::IControl::Draw
//
// Calls the embedded object and tells it to paint itself.
//
STDMETHODIMP
CXSite::Draw(DrawContext* inContext)
{
if ( mControlP )
mControlP->Draw(inContext);
else
mCachedDraw = true;
return S_OK;
}
//
// CBaseSite::IControl::OnContextChange
//
// Adds a context to the control
//
STDMETHODIMP
CXSite::OnContextChange(UInt32 inContextID, ContextCommand inCommand)
{
if ( mControlP )
return mControlP->OnContextChange(inContextID, inCommand);
else
{
mCachedContextChange = true;
if (inCommand == ActivateContext)
mCachedActiveContextID = inContextID;
else if (inCommand == DeactivateContext)
mCachedActiveContextID = InvalidContextID;
return S_OK;
}
}
//
// CBaseSite::IControl::GetID
//
// Returns the ID of the control
//
STDMETHODIMP
CXSite::GetID(Int32 inBufferSize, Char8* outID)
{
if ( mControlP )
return mControlP->GetID(inBufferSize, outID);
else
{
outID[0] = 0; // return null string
return E_FAIL;
}
}
//
// CBaseSite::IControl::GetUsedArea
//
// Returns the used area of the control
//
STDMETHODIMP
CXSite::GetUsedArea(PlatformRegion* outUsedArea)
{
if ( mControlP )
return mControlP->GetUsedArea(outUsedArea);
else
return E_FAIL;
}
//
// CBaseSite::IControl::SetFocus
//
// Sets or removes focus from this site
//
STDMETHODIMP
CXSite::SetFocus(FocusCommand inCommand, FocusSet inFocus)
{
ErrorCode theResult = S_OK;
if ( mControlP )
theResult = mControlP->SetFocus(inCommand, inFocus);
else
theResult = E_FAIL;
return theResult;
}
//
// CBaseSite::IControl::DoMouse
//
STDMETHODIMP
CXSite::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
{
ErrorCode theResult = S_OK;
if ( mControlP )
theResult = mControlP->DoMouse(inMouseET, inEvent);
return theResult;
}
//
// CBaseSite::IControl::DoKey
//
STDMETHODIMP
CXSite::DoKey(KeyEventType inKeyET, Char8 inChar, PlatformEvent* inEvent)
{
ErrorCode theResult = S_OK;
if ( mControlP )
theResult = mControlP->DoKey(inKeyET, inChar, inEvent);
return theResult;
}
//
// CBaseSite::IControl::DoActivate
//
STDMETHODIMP
CXSite::DoActivate(ActivateEventType inActiveET, UInt32 inContextID, PlatformEvent* inEvent)
{
ErrorCode theResult = S_OK;
if ( mControlP )
theResult = mControlP->DoActivate(inActiveET, inContextID, inEvent);
return theResult;
}
//
// CBaseSite::IControl::DoSystemEvent
//
STDMETHODIMP
CXSite::DoSystemEvent(PlatformEvent* inEvent)
{
ErrorCode theResult = S_OK;
if ( mControlP )
theResult = mControlP->DoSystemEvent(inEvent);
return theResult;
}
//
// CBaseSite::IControl::OnIdle
//
// pass idle events to the control
//
STDMETHODIMP
CXSite::DoIdle(Uint32 IdleRefCon)
{
if ( mControlP )
return mControlP->DoIdle(IdleRefCon);
else
return SetIdleTime(RemoveAllIdlers, NULL);
}
#pragma mark === CBaseSite::IServiceProvider Interface ===
//
// CBaseSite::IServiceProvider::QueryService
//
STDMETHODIMP
CXSite::QueryService(REFGUID inRSID, REFIID inRefID, void** outObj)
{
ErrorCode Result;
if (inRSID == SID_BindHost)
{
// According to the "OLE Controls/COM Objects for the Internet" spec,
// it's legal for the site to implement this service directly on the
// site object.
Result = this->QueryInterface(inRefID, outObj);
}
else if ( inRSID == SID_IThreads )
Result = this->QueryInterface(inRefID, outObj);
else
{
*outObj = NULL;
Result = E_NOINTERFACE;
}
return Result;
}
#pragma mark === CBaseSite::IThreadScheduler Interface ===
//
// CBaseSite::IThreadScheduler::GetScheduler
//
STDMETHODIMP
CXSite::GetScheduler(ProcPtr* outScheduler)
{
*outScheduler = mThreadScheduler;
if ( mThreadScheduler )
return S_OK;
else
return S_FALSE;
}
#pragma mark === Static Utility Functions ===
//
// toLower
//
static void toLower(char* src)
{
for(char * p = src;*p; p++){
*p = tolower(*p);
}
}
//
// StrDup
//
static LPOLESTR StrDup(LPCOLESTR psz)
{
LPOLESTR pszDup;
if ((pszDup = (LPOLESTR) NewPtr(strlen((char *) psz) + 1)) != NULL)
strcpy((char *) pszDup, (const char *) psz);
return pszDup;
}